import React from 'react'
import ReactDOM from 'react-dom'
import moment from 'moment'
import cssStyle from './index.module.css'
import arrow from '@/assets/images/arrow-gray.png'
import PropTypes from 'prop-types'
import { Tag } from '@/component'

class CalendarComponent extends React.PureComponent{
    constructor(props){
        super(props)
        let date
        if(!props.value){
            date = new Date()
        }else{
            date = new Date(moment(props.value).format())
        }
        this.state = this.init(date)
        this.clickListener = this.clickListener.bind(this)
        this.remove = this.remove.bind(this)
        this.timer = null
        this.ref = React.createRef()
        this.locationListener = null
    }
    init = date => {
        let currentYear = date.getFullYear()
        let currentMonth = date.getMonth() + 1
        let currentDay = date.getDate()
        let week = date.getDay()

        let isLeap = false
        if((currentYear%100 !==0 && currentYear%4 === 0) || currentYear%400 === 0){
            isLeap = true
        }
        let monthDay = {
            1: 31,
            2: isLeap ? 29 : 28,
            3: 31,
            4: 30,
            5: 31,
            6: 30,
            7: 31,
            8: 31,
            9: 30,
            10: 31,
            11: 30,
            12: 31
        }
        let borrowPrev = []
        let n = week - currentDay%7 + 1
        if(n <= 0){
            n += 7
        }
        let prevMonth = currentMonth - 1 === 0 ? 12 : currentMonth - 1
        for(let i = monthDay[prevMonth]; i > monthDay[prevMonth] - n; i--){
            borrowPrev.push(i)
        }
        borrowPrev = borrowPrev.reverse()

        let restNext = 7 - (monthDay[currentMonth] + borrowPrev.length)%7
        let borrowNext = []
        for(let i = 1; i <= restNext; i++){
            borrowNext.push(i)
        }

        let currentMonthDays = []
        for(let i = 1; i <= monthDay[currentMonth]; i++){
            currentMonthDays.push(i)
        }

        if((borrowPrev.length + currentMonthDays.length + borrowNext.length) === 35){
            let end = borrowNext[borrowNext.length - 1]
            for(let i = end + 1; i <= end + 7; i++){
                borrowNext.push(i)
            }
        }
        return{
            borrowPrev,
            currentMonthDays,
            borrowNext,
            currentYear,
            currentMonth,
            currentDay
        }
    }
    prevNextMonth = type =>{
        let year = this.state.currentYear
        let month = this.state.currentMonth
        let currentYear, currentMonth, currentDay = 1
        if(type === 'prev'){
            if(month === 1){
                currentYear = year - 1
                currentMonth = 12
            }else{
                currentYear = year
                currentMonth = --month
            }
        }else if(type === 'next'){
            if(month === 12){
                currentYear = year + 1
                currentMonth = 1
            }else{
                currentYear = year
                currentMonth = month + 1
            }
        }else{
            let date = new Date()
            currentYear = date.getFullYear()
            currentMonth = date.getMonth() + 1
            currentDay =date.getDate()
        }
        let calendarData = this.init(new Date(currentYear, --currentMonth, currentDay))
        this.setState(calendarData)
    }
    turn = (day, type) => {
        let year = this.state.currentYear
        let month = this.state.currentMonth
        let currentYear, currentMonth, currentDay = day
        if(type === 'prev'){
            if(month === 1){
                currentYear = year - 1
                currentMonth = 12
            }else{
                currentYear = year
                currentMonth = --month
            }
        }else if(type === 'next'){
            if(month === 12){
                currentYear = year + 1
                currentMonth = 1
            }else{
                currentYear = year
                currentMonth = month + 1
            }
        }else{
            currentYear = year
            currentMonth = month
        }
        let calendarData = this.init(new Date(currentYear, --currentMonth, currentDay))
        this.setState(calendarData)
    }
    confirm = () => {
        let calendar = this.state.currentYear + '-' + (this.state.currentMonth < 10 ? ('0' + this.state.currentMonth) : this.state.currentMonth) + '-' + (this.state.currentDay < 10 ? ('0' + this.state.currentDay) : this.state.currentDay)
        this.props.confirm(calendar, this.props.current)
    }
    clickListener = e => {
        if(!this.ref.current.contains(e.target)){
            this.props.toggle(this.props.current)
        }
    }
    remove = () => {
        this.props.remove()
    }
    locationChange = () => {
        if(this.locationListener){
            window.cancelAnimationFrame(this.locationListener)
            this.locationListener = null
        }
        this.locationListener = window.requestAnimationFrame(() => {
            let { left, top } = this.getLocation()
            this.ref.current.style.top = top + 'px'
            this.ref.current.style.left = left + 'px'
            this.locationChange()
        })
    }
    getLocation = () => {
        let location = this.props.current.getBoundingClientRect()
        let top = location.bottom
        let currentHeight = this.ref.current.children[0].clientHeight
        let bodyHeight = document.documentElement.clientHeight
        if(top + currentHeight > bodyHeight){
            top = top - currentHeight - (location.height) - 2
        }
        return {
            left: location.left,
            top
        }
    }
    show = () => {
        let { left, top } = this.getLocation()
        this.ref.current.style.top = top + 'px'
        this.ref.current.style.left = left + 'px'
        this.ref.current.style.opacity = 1
        this.ref.current.style.height = this.ref.current.children[0].clientHeight + 'px'
        this.locationChange()
        setTimeout(() => {
            window.removeEventListener('click', this.clickListener)
            window.addEventListener('click', this.clickListener)
        }, 300)
    }
    componentDidUpdate(){
        if(this.timer){
            return
        }
        if(this.props.open){
            if(this.props.current){
                this.show()
            }
        }else{
            if(this.locationListener){
                window.cancelAnimationFrame(this.locationListener)
                this.locationListener = null
            }
            this.ref.current.style.height = 0
            this.ref.current.style.opacity = 0
            this.timer = setTimeout(() => {
                clearTimeout(this.timer)
                this.timer = null
                window.removeEventListener('click', this.clickListener)
            }, 300)
        }
    }
    componentDidMount(){
        this.show()
        window.addEventListener('hashchange', this.remove)
    }
    componentWillUnmount(){
        window.removeEventListener('click', this.clickListener)
        window.removeEventListener('hashchange', this.remove)
    }
    render(){
        return(
            <div className={ cssStyle.calendarMain } onClick={ e => { e.stopPropagation() } } ref={ this.ref }>
                <div className={ cssStyle.calendar }>
                    <div className={ cssStyle.prevNext }>
                        <span>{ this.state.currentYear + '-' + (this.state.currentMonth < 10 ? ('0' + this.state.currentMonth) : this.state.currentMonth) + '-' + (this.state.currentDay < 10 ? ('0' + this.state.currentDay) : this.state.currentDay) }</span>
                        <div className={ cssStyle.calendarSwitch }>
                            <span onClick={ (() => { this.prevNextMonth('prev') }) }>上个月</span>
                            <span onClick={ (() => { this.prevNextMonth('now') }) }>回到今天</span>
                            <span onClick={ (() => { this.prevNextMonth('next') }) }>下个月</span>
                        </div>
                    </div>
                    <div>
                        <span>日</span>
                        <span>一</span>
                        <span>二</span>
                        <span>三</span>
                        <span>四</span>
                        <span>五</span>
                        <span>六</span>
                    </div>
                    <div className={ cssStyle.calendarItem }>
                        {
                            
                            this.state.borrowPrev.map((item, index) => {
                                return <span key={ index } className={ cssStyle.gray } onClick={ () => { this.turn(item, 'prev') } }>{ item }</span>
                            })
                        }
                        {
                            
                            this.state.currentMonthDays.map((item, index) => {
                                return <span key={ index } className={ item === this.state.currentDay ? cssStyle.calendarActive : '' } onClick={ () => { this.turn(item) } }>{ item }</span>
                            })
                        }
                        {
                            
                            this.state.borrowNext.map((item, index) => {
                                return <span key={ index } className={ cssStyle.gray } onClick={ () => { this.turn(item, 'next') } }>{ item }</span>
                            })
                        }
                    </div>
                    <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '10px' }}>
                        <Tag size="small" style={{ width: 'unset', height: 'unset', lineHeight: 'unset', marginRight: '10px' }} onClick={ () => { this.props.toggle(this.props.current) } }>取消</Tag>
                        <Tag type="primary" size="small" style={{ width: 'unset', height: 'unset', lineHeight: 'unset' }} onClick={ this.confirm }>确定</Tag>
                    </div>
                </div>
            </div>
        )
    }
}

CalendarComponent.propTypes = {
    confirm: PropTypes.func,
    toggle: PropTypes.func,
    current: PropTypes.object,
    open: PropTypes.bool,
    remove: PropTypes.func,
    value: PropTypes.string
}

class Calendar extends React.PureComponent{
    constructor(props){
        super(props)
        this.open = false
        this.toggle = this.toggle.bind(this)
        this.selectRef = React.createRef()
        this.arrowRef = React.createRef()
        this.calendarComponent = null
    }
    toggleCalendarComponent = (open, current) => {
        if(open){
            if(!this.calendarComponent){
                this.calendarComponent = document.createElement('div')
                document.body.appendChild(this.calendarComponent)
            }
        }
        ReactDOM.render(
            <CalendarComponent {...this.props} open={ open } current={ current } toggle={ this.toggle.bind(this) } confirm={ this.confirm.bind(this) } remove={ this.remove.bind(this) } />,
            this.calendarComponent
        )
    }
    remove = () => {
        ReactDOM.unmountComponentAtNode(this.calendarComponent)
        document.body.removeChild(this.calendarComponent)
        this.calendarComponent = null
    }
    toggle = current => {
        this.open = !this.open
        if(this.open){
            this.arrowRef.current.style.transform = 'translateY(-50%) rotate(180deg)'
            current.children[0].style.borderColor = '#409eff'
        }else{
            if(this.arrowRef.current){
                this.arrowRef.current.style.transform = 'translateY(-50%) rotate(0)'
                if(this.props.invalid){
                    current.children[0].style.borderColor = 'red'
                }else{
                    current.children[0].style.borderColor = '#dcdfe6'
                }
            }
        }
        this.toggleCalendarComponent(this.open, current)
    }
    confirm = (calendar, current) => {
        if(this.props.onChange){
            this.props.onChange(calendar)
        }
        this.toggle(current)
    }
    render(){
        let invalidStyle = {}
        if(this.props.invalid){
            invalidStyle.borderColor = 'red'
        }
        return(
            <div className={ cssStyle.select } style={ this.props.style } ref={ this.selectRef }
                onClick={
                    e => {
                        if(this.open){
                            e.stopPropagation()
                        }
                        this.toggle(this.selectRef.current)
                    } 
                }
            >
                <div className={ cssStyle.selectInput } style={{ ...invalidStyle }}>
                    <div>
                        <div style={{ cursor: 'pointer', textOverflow: 'ellipsis' }}>
                            {
                                this.props.value !== ''
                                ?
                                <span>{ moment(this.props.value).format('YYYY-MM-DD') }</span>
                                :
                                <span style={{ color: '#999' }}>{ this.props.placeholder }</span>
                            }
                        </div>
                        <img ref={ this.arrowRef } src={ arrow } alt="arrow" />
                    </div>
                </div>
            </div>
        )
    }
}

Calendar.propTypes = {
    onChange: PropTypes.func,
    value: PropTypes.string,
    placeholder: PropTypes.string,
    style: PropTypes.object,
    invalid: PropTypes.bool
}

export {
    Calendar
}